package org.pearl.springboot.minio.sdk;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import com.google.common.io.ByteStreams;
import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import io.minio.messages.*;
import me.tongfei.progressbar.ProgressBarStyle;
import okhttp3.*;
import org.apache.commons.io.FileUtils;

import java.io.*;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.time.ZonedDateTime;
import java.util.*;

/**
 * Created by TD on 2021/10/19
 */
public class MinioPutObject {
    /**
     * MinioClient.putObject() example.
     */
    public static void main(String[] args)
            throws IOException, NoSuchAlgorithmException, InvalidKeyException {
        try {
            // 初始化客户端
            MinioClient minioClient =
                    MinioClient.builder()
                            // minio服务端地址URL
                            .endpoint("http://localhost:9000")
                            // 用户名及密码（访问密钥/密钥）
                            .credentials("admin", "admin123")
                            .build();

            // 1. 创建InputStream上传
/*            File file = new File("D:\\deploy\\nacos-server-2.0.3.tar.gz");
            InputStream bais = new FileInputStream(file);
            long start = System.currentTimeMillis();
            minioClient.putObject(
                    PutObjectArgs.builder().bucket("my-bucketname").object(file.getName()).stream(
                            bais, bais.available(), -1)
                            .build());
            bais.close();
            System.out.println("my-objectname is uploaded successfully 耗时：" + (System.currentTimeMillis() - start));*/
// Create a InputStream for object upload.
            // 上传文件 添加自定义元数据及消息头
/*            File file = new File("D:\\deploy\\nacos-server-2.0.3.tar.gz");
            InputStream bais = new FileInputStream(file);
            Map<String, String> headers = new HashMap<>();
            headers.put("Content-Type", "application/octet-stream");
            headers.put("X-Amz-Storage-Class", "REDUCED_REDUNDANCY");
            Map<String, String> userMetadata = new HashMap<>();
            minioClient.putObject(
                    PutObjectArgs.builder().bucket("my-bucketname").object("my-objectname").stream(
                            bais, bais.available(), -1)
                            .headers(headers)
                            .userMetadata(userMetadata)
                            .build());
            bais.close();
            System.out.println("my-objectname is uploaded successfully");


            // 2. 获取对象的InputStream,并保存为文件
            InputStream stream =
                    minioClient.getObject(
                            GetObjectArgs.builder().bucket("my-bucketname").object("my-objectname").build());
            // 读流
            File targetFile = new File("D:\\deploy\\targetFile.tmp");
            FileUtils.copyInputStreamToFile(stream, targetFile);
            stream.close();*/

            // 3. 将本地文件上传到minio
/*            minioClient.uploadObject(
                    UploadObjectArgs.builder()
                            .bucket("my-bucketname")
                            .object("start.sh")
                            .filename("D:\\deploy\\service\\general-task\\start.sh")
                            .build());
            System.out.println("my-filename is uploaded to my-objectname successfully");*/
            // 4. 下载对象到本地文件
/*            minioClient.downloadObject(
                    DownloadObjectArgs.builder()
                            .bucket("my-bucketname")
                            .object("my-objectname")
                            .filename("D:\\deploy\\service\\general-task\\aaa.tmp")
                            .build());
            System.out.println("my-objectname is successfully downloaded to my-filename");*/

            // Create object "my-objectname" in bucket "my-bucketname" by copying from object
            // "my-objectname" in bucket "my-source-bucketname".
            // 5. 将my-bucketname中的aa.tmp文件，复制到aaaaa桶下的bb.tmp对象
            /*minioClient.copyObject(
                    CopyObjectArgs.builder()
                            .bucket("aaaaa")
                            .object("bb.tmp")
                            .source(
                                    CopySource.builder()
                                            .bucket("my-bucketname")
                                            .object("aa.tmp")
                                            .build())
                            .build());
            System.out.println("successfully");*/

            // 6. 删除单个对象
/*            minioClient.removeObject(
                    RemoveObjectArgs.builder().bucket("aaaaa").object("bb.tmp").build());*/
            // 删除指定版本号的对象
            /*minioClient.removeObject(
                    RemoveObjectArgs.builder()
                            .bucket("my-bucketname")
                            .object("my-versioned-objectname")
                            .versionId("my-versionid")
                            .build());*/
            // 7. 删除多个文件
           /* List<DeleteObject> objects = new LinkedList<>();
            objects.add(new DeleteObject("aa.tmp"));
            objects.add(new DeleteObject("my-objectname"));
            objects.add(new DeleteObject("nacos-server-2.0.3.tar.gz"));
            Iterable<Result<DeleteError>> results =
                    minioClient.removeObjects(
                            RemoveObjectsArgs.builder().bucket("my-bucketname").objects(objects).build());
            for (Result<DeleteError> result : results) {
                DeleteError error = result.get();
                System.out.println(
                        "Error in deleting object " + error.objectName() + "; " + error.message());
            }*/

            // 8. 查询存储桶下文件信息
            /*Iterable<Result<Item>> results =
                    minioClient.listObjects(ListObjectsArgs.builder().bucket("my-bucketname").build());
            for (Result<Item> result : results) {
                Item item = result.get();
                System.out.println(item.lastModified() + "\t" + item.size() + "\t" + item.objectName());
            }*/
            /*Iterable<Result<Item>> results =
                    minioClient.listObjects(
                            ListObjectsArgs.builder().bucket("my-bucketname").recursive(true).build());

            for (Result<Item> result : results) {
                Item item = result.get();
                System.out.println(item.lastModified() + "\t" + item.size() + "\t" + item.objectName());
            }*/
            // 条件查询，指定前缀、后缀、最大数量
/*
            Iterable<Result<Item>> results =
                    minioClient.listObjects(
                            ListObjectsArgs.builder()
                                    .bucket("my-bucketname")
                                    .startAfter("ExampleGuide.pdf")
                                    .prefix("E")
                                    .maxKeys(100)
                                    .build());
            for (Result<Item> result : results) {
                Item item = result.get();
                System.out.println(item.lastModified() + "\t" + item.size() + "\t" + item.objectName());
            }
*/


            // Declaring config with Retention mode as Compliance and
            // retain until 3 days from current date.

            // 对象保留配置，保留至当前日期后3天。
/*
            ZonedDateTime retentionUntil = ZonedDateTime.now(Time.UTC).plusDays(3).withNano(0);
            Retention retention1 = new Retention(RetentionMode.COMPLIANCE, retentionUntil);
            minioClient.setObjectRetention(
                    SetObjectRetentionArgs.builder()
                            .bucket("bbb")
                            .object("k3s-install.sh")
                            .config(retention1)
                            .bypassGovernanceMode(true)
                            .build());
*/

/*            // 获取对象保留配置
            Retention retention =
                    minioClient.getObjectRetention(
                            GetObjectRetentionArgs.builder()
                                    .bucket("my-bucketname-in-eu-with-object-lock")
                                    .object("k3s-arm64")
                                    .build());

            System.out.println("Mode: " + retention.mode());
            System.out.println("Retainuntil Date: " + retention.retainUntilDate());*/


/*            Map<String, String> map = new HashMap<>();
            map.put("Project", "Project One");
            map.put("User", "jsmith");
            minioClient.setObjectTags(
                    SetObjectTagsArgs.builder()
                            .bucket("my-bucketname")
                            .object("my-objectname")
                            .tags(map)
                            .build());
            Tags tags =
                    minioClient.getObjectTags(
                            GetObjectTagsArgs.builder().bucket("my-bucketname").object("my-objectname").build());
            System.out.println("Object tags: " + tags.get());*/

            // 指定一个GET请求，返回获取文件对象的URL，此URL过期时间为一天
/*
            String url =
                    minioClient.getPresignedObjectUrl(
                            GetPresignedObjectUrlArgs.builder()
                                    .method(Method.GET)
                                    .bucket("my-bucketname")
                                    .object("start.sh")
                                    .expiry(60 * 60 * 24)
                                    .build());
            System.out.println(url);

*/                  // 3. 将保留模式设置为Compliance，且持续时间为100天的
            // 设置锁定对象的保留模式及时限

            // 1. 上传一个文件
            // 写
            String policy =
                    minioClient.getBucketPolicy(
                            GetBucketPolicyArgs.builder().bucket("aaaaa").build());
            System.out.println("Current policy: " + policy);
            System.out.println("===================== write");
            byte[] data =
                    ("Year,Make,Model,Description,Price\n"
                            + "1997,Ford,E350,\"ac, abs, moon\",3000.00\n"
                            + "1999,Chevy,\"Venture \"\"Extended Edition\"\"\",\"\",4900.00\n"
                            + "1999,Chevy,\"Venture \"\"Extended Edition, Very Large\"\"\",,5000.00\n"
                            + "1996,Jeep,Grand Cherokee,\"MUST SELL!\n"
                            + "air, moon roof, loaded\",4799.00\n")
                            .getBytes(StandardCharsets.UTF_8);

            ByteArrayInputStream bais = new ByteArrayInputStream(data);
            ObjectWriteResponse response = minioClient.putObject(
                    PutObjectArgs.builder().bucket("aaaaa").object("my-objectname").stream(
                            bais, data.length, -1)
                            .build());
            System.out.println(response);




            InputStream stream =
                    minioClient.getObject(
                            GetObjectArgs.builder().bucket("aaaaa").object("my-objectname").versionId("aadsadsafsa").build());
            // 读流
            File targetFile = new File("D:\\deploy\\targetFile.tmp");
            FileUtils.copyInputStreamToFile(stream, targetFile);
            stream.close();
           /* // 调用SQL表达式获取对象
            String sqlExpression = "select * from S3Object";
            InputSerialization is =
                    new InputSerialization(null, false, null, null, FileHeaderInfo.USE, null, null, null);
            OutputSerialization os =
                    new OutputSerialization(null, null, null, QuoteFields.ASNEEDED, null);

            SelectResponseStream stream =
                    minioClient.selectObjectContent(
                            SelectObjectContentArgs.builder()
                                    .bucket("my-bucketname")
                                    .object("my-objectName")
                                    .sqlExpression(sqlExpression)
                                    .inputSerialization(is)
                                    .outputSerialization(os)
                                    .requestProgress(true)
                                    .build());

            byte[] buf = new byte[512];
            int bytesRead = stream.read(buf, 0, buf.length);
            System.out.println(new String(buf, 0, bytesRead, StandardCharsets.UTF_8));
            Stats stats = stream.stats();
            System.out.println("bytes scanned: " + stats.bytesScanned());
            System.out.println("bytes processed: " + stats.bytesProcessed());
            System.out.println("bytes returned: " + stats.bytesReturned());
            stream.close();


            minioClient.enableObjectLegalHold(
                    EnableObjectLegalHoldArgs.builder()
                            .bucket("my-bucketname")
                            .object("my-objectname")
                            .versionId("object-versionId")
                            .build());

            System.out.println("Legal hold enabled on object successfully ");


            List<ComposeSource> sources = new ArrayList<ComposeSource>();
            sources.add(
                    ComposeSource.builder()
                            .bucket("my-bucketname-one")
                            .object("my-objectname-one")
                            .build());
            sources.add(
                    ComposeSource.builder()
                            .bucket("my-bucketname-two")
                            .object("my-objectname-two")
                            .build());

            ObjectWriteResponse objectWriteResponse = minioClient.composeObject(
                    ComposeObjectArgs.builder()
                            .bucket("my-destination-bucket")
                            .object("my-destination-object")
                            .sources(sources)
                            .build());
            System.out.println("Object Composed successfully");
*/


/*            // 为存储桶创建一个上传策略，过期时间为7天
            PostPolicy policy = new PostPolicy("my-bucketname", ZonedDateTime.now().plusDays(7));
            // 设置一个参数key，值为上传对象的名称
            policy.addEqualsCondition("key", "my-objectname");
            // 添加Content-Type以"image/"开头，表示只能上传照片
            policy.addStartsWithCondition("Content-Type", "image/");
            // 设置上传文件的大小 64kiB to 10MiB.
            policy.addContentLengthRangeCondition(64 * 1024, 10 * 1024 * 1024);
            Map<String, String> formData = minioClient.getPresignedPostFormData(policy);

            // 创建MultipartBody对象
            MultipartBody.Builder multipartBuilder = new MultipartBody.Builder();
            multipartBuilder.setType(MultipartBody.FORM);
            for (Map.Entry<String, String> entry : formData.entrySet()) {
                multipartBuilder.addFormDataPart(entry.getKey(), entry.getValue());
            }
            multipartBuilder.addFormDataPart("key", "my-objectname");
            multipartBuilder.addFormDataPart("Content-Type", "image/png");
            multipartBuilder.addFormDataPart(
                    "file", "my-objectname", RequestBody.create(new File("D:\\deploy\\service\\general-task\\logs\\aa.png"), null));
            // 模拟第三方，使用OkHttp调用Post上传对象
            Request request =
                    new Request.Builder()
                            .url("http://localhost:9000/my-bucketname")
                            .post(multipartBuilder.build())
                            .build();
            OkHttpClient httpClient = new OkHttpClient().newBuilder().build();
            Response response = httpClient.newCall(request).execute();
            if (response.isSuccessful()) {
                System.out.println("Pictures/avatar.png is uploaded successfully using POST object");
            } else {
                System.out.println("Failed to upload Pictures/avatar.png");
            }

            // Print curl command usage to upload file /tmp/userpic.jpg.
            System.out.print("curl -X POST ");
            for (Map.Entry<String, String> entry : formData.entrySet()) {
                System.out.print(" -F " + entry.getKey() + "=" + entry.getValue());
            }
            System.out.print(" -F key=my-objectname -F Content-Type=image/jpg");
            System.out.println(" -F file=@/tmp/userpic.jpg https://play.min.io/my-bucketname");*/

/*            // 查询元数据
            StatObjectResponse stat =
                    minioClient.statObject(
                            StatObjectArgs.builder()
                                    .bucket("my-bucketname")
                                    .object("start.sh")
                                    .build());
            System.out.println(stat.toString());*/


        } catch (InvalidResponseException | InsufficientDataException | ErrorResponseException | InternalException | ServerException | XmlParserException | BucketPolicyTooLargeException ex) {
            ex.printStackTrace();
        }


    }
}